package org.budo.dubbo.protocol.async.repository.aliyun.mns;

import org.budo.dubbo.protocol.async.repository.AbstractAsyncRepository;

import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.common.utils.Assert;
import com.alibaba.dubbo.common.utils.StringUtils;
import com.aliyun.mns.client.CloudAccount;
import com.aliyun.mns.client.CloudQueue;
import com.aliyun.mns.client.MNSClient;
import com.aliyun.mns.model.QueueMeta;

import lombok.Getter;
import lombok.Setter;

/**
 * @author lmw
 */
@Getter
@Setter
public abstract class AbstractAliyunMnsAsyncRepository extends AbstractAsyncRepository {
    private static final Logger log = LoggerFactory.getLogger(AbstractAliyunMnsAsyncRepository.class);

    private String accessId;

    private String accessKey;

    private String accountEndpoint;

    /**
     * 消息拉取超时
     */
    private Integer popWaitSeconds = 15;

    /**
     * 每次拉取消息数
     */
    private Integer popBatchSize = 5;

    private MNSClient mnsClient;

    /**
     * 返回对应一个异步方法的队列，如果没有就创建
     */
    protected CloudQueue getInterfaceQueue(Class<?> interfaceType, String destinationName) {
        Assert.notNull(interfaceType, "#72 interfaceType can not be null");

        CloudQueue cloudQueue = this.getMnsClient().getQueueRef(destinationName);

        // 检查消息队列是否存在，可读
        if (this.canGetAttributes(cloudQueue)) {
            return cloudQueue;
        }

        // 检查消息队列名称是否符合规则
        this.checkQueueName(destinationName);

        log.info("#80 Create queue destinationName=" + destinationName + ", cloudQueue=" + cloudQueue + ", interfaceType=" + interfaceType + ", this=" + this);

        QueueMeta queueMeta = new QueueMeta();
        queueMeta.setQueueName(destinationName);
        queueMeta.setPollingWaitSeconds(this.getPopWaitSeconds());
        cloudQueue.create(queueMeta);
        return cloudQueue;
    }

    private MNSClient getMnsClient() {
        if (null != this.mnsClient) {
            return this.mnsClient;
        }

        synchronized (this) {
            if (null != this.mnsClient) {
                return this.mnsClient;
            }

            return this.mnsClient = this.initMnsClient();
        }
    }

    private MNSClient initMnsClient() {
        String accessId = this.getAccessId();
        String accessKey = this.getAccessKey();
        String accountEndpoint = this.getAccountEndpoint();

        CloudAccount account = new CloudAccount(accessId, accessKey, accountEndpoint);
        return account.getMNSClient();
    }

    /**
     * 检查消息队列是否存在，可读
     */
    private Boolean canGetAttributes(CloudQueue queue) {
        try {
            queue.getAttributes();
            return true;
        } catch (Exception e) {
            log.warn("#18 isQueueExists, queue.getAttributes() error, queue=" + queue + ", e=" + e);
            return false;
        }
    }

    /**
     * 检查消息队列名称是否符合规则
     */
    private void checkQueueName(String queueName) {
        if (StringUtils.isEmpty(queueName)) {
            throw new IllegalArgumentException("#26 queueName can not be empty, queueName=" + queueName);
        }

        if (queueName.startsWith("-")) {
            throw new IllegalArgumentException("#30 queueName can not start with -, queueName=" + queueName);
        }

        if (queueName.contains(".")) {
            throw new IllegalArgumentException("#34 queueName can not contains dot('.'), queueName=" + queueName);
        }
    }
}